home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 7
/
Aminet 7 - August 1995.iso
/
Aminet
/
comm
/
tcp
/
AmigaTCP.lha
/
AmigaTCP
/
src
/
smtpcli.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-24
|
8KB
|
307 lines
/* smtpcli.c
* Client routines for Simple Mail Transfer Protocol ala RFC821
* A.D. Barksdale Garbee II, aka Bdale, N3EUA
* Copyright 1986 Bdale Garbee, All Rights Reserved.
* Permission granted for non-commercial copying and use, provided
* this notice is retained.
*/
#include <stdio.h>
#include "machdep.h"
#include "netuser.h"
#include "mbuf.h"
#include "timer.h"
#include "tcp.h"
#include "smtp.h"
extern int16 lport; /* local port placeholder */
int32 aton();
static void sendit();
static struct timer smtpcli_t;
char *index(),*rindex();
/* init routine called when program fired up */
smtpclinit()
{
int dosmtptick();
smtpcli_t.func = (void (*)())dosmtptick;/* what to call on timeout */
smtpcli_t.arg = 0; /* dummy value */
smtpcli_t.start = SMTPCLITIME; /* set timer duration */
start_timer(&smtpcli_t); /* and fire it up */
}
/* this is the routine that gets called every so often to do outgoing mail
processing */
int
dosmtptick()
{
char lfilename[LINELEN],
tmpstring[LINELEN],
wfilename[13],
*ptr;
FILE *lfile;
struct smtp_msg *mp;
struct socket lsocket, fsocket;
char *calloc(),*malloc();
void smtp_rec(), smtp_cts(), smtp_state();
/* printf("DOSMTPTICK() entered\n"); */
lsocket.address = ip_addr; /* our ip address */
fsocket.port = SMTP_PORT;
/* if lock file exists in mqueue dir, return */
sprintf(lfilename,"%s%s",MAILQDIR,"lockfile");
if ((lfile = fopen(lfilename,"x")) == NULL)
return;
/* get next work filename from mqueue directory */
sprintf(tmpstring,"%s%s",MAILQDIR,"*.wrk");
#ifndef AMIGA
filedir(tmpstring,0,wfilename);
#endif
if (wfilename[0] == '\0')
return; /* no work to be done */
/* if we have work, rebuild the exact (non-wild) filename */
mp = (struct smtp_msg *)calloc(1,sizeof (struct smtp_msg));
sprintf(tmpstring,"%s%s",MAILQDIR,wfilename);
ptr = &tmpstring[0];
mp->filename = malloc((unsigned)strlen(ptr)+1);
strcpy(mp->filename,ptr);
/* printf("work file name: %s\n",mp->filename); /* debug only */
mp->wfile = fopen(mp->filename,"r");
/* get ip address, from stuff, to stuff */
fgets(tmpstring,LINELEN,mp->wfile); /* read target ip addr */
/* printf("target ip addr: %s\n",tmpstring); */
fgets(mp->toaddr,LINELEN,mp->wfile); /* who to */
rip(mp->toaddr);
/* printf("addressee: %s\n",mp->toaddr); */
fgets(mp->fromaddr,LINELEN,mp->wfile); /* who from */
rip(mp->fromaddr);
/* printf("sender: %s\n",mp->fromaddr); */
fclose(mp->wfile);
/* set up the rest of the socket info from what we got */
fsocket.address = aton(tmpstring); /* destination ip address */
lsocket.port = lport++; /* next unused port */
/* open smtp connection */
mp->state = CLI_OPEN_STATE; /* init state placeholder */
/* printf("Opening TCP connection for SMTP client\n"); */
mp->tcb = open_tcp(&lsocket,&fsocket,TCP_ACTIVE,1024,
smtp_rec,smtp_cts,smtp_state,0,(int *)mp);
mp->tcb->user = (int *)mp; /* Upward pointer */
/* printf("releasing lock\n"); */
if (lfile != NULL) { /* release lock */
fclose(lfile);
unlink(lfilename);
}
}
/* replace terminating end of line marker(s) with null */
rip(s)
char *s;
{
char *c;
c=s;
while (*c != '\0') {
switch (*c) {
case '\r':
case '\n':
*c='\0';
break;
default:
c++;
break;
}
}
}
/* this is the master state machine that handles a single SMTP transaction */
smtp_transaction(mp)
struct smtp_msg *mp;
{
char tmpstring[LINELEN]; /* where we build command lines */
/* printf("SMTP_TRANSACTION() called, state=%u\n",mp->state); */
if (affirmative(mp)) {
switch(mp->state) {
case CLI_OPEN_STATE:
mp->state = CLI_MAIL_STATE;
/* issue MAIL command */
/* printf("FROMADDR = %s\n",mp->fromaddr); */
sprintf(tmpstring,"mail from:<%s>\r\n",mp->fromaddr);
sendit(mp,tmpstring);
break;
case CLI_MAIL_STATE:
mp->state = CLI_RCPT_STATE;
/* issue RCPT command */
sprintf(tmpstring,"rcpt to:<%s>\r\n",mp->toaddr);
sendit(mp,tmpstring);
break;
case CLI_RCPT_STATE:
mp->state = CLI_SEND_STATE;
/* open text file */
strcpy(tmpstring,mp->filename);
strcpy(index(tmpstring,'.'),".txt");
/* printf("text filename: %s",tmpstring); */
mp->tfile = fopen(tmpstring,"r");
/* issue DATA command */
sprintf(tmpstring,"data\r\n");
sendit(mp,tmpstring);
break;
case CLI_SEND_STATE:
/* the transmitter upcall routine will advance the
state pointer on end of file, so we do nada... */
break;
case CLI_UNLK_STATE:
unlink(mp->filename); /* unlink workfile */
/* close and unlink the textfile */
fclose(mp->tfile);
strcpy(tmpstring,mp->filename);
strcpy(index(tmpstring,'.'),".txt");
unlink(tmpstring);
mp->state = CLI_QUIT_STATE;
/* issue a quit command */
sprintf(tmpstring,"quit\r\n");
sendit(mp,tmpstring);
break;
case CLI_QUIT_STATE:
/* either start next transaction, or quit */
close_tcp(mp->tcb); /* close up connection */
break;
}
} else { /* if we get here, means we got a negative reply */
/* for the moment, just let that hose us... */
mp->state = CLI_QUIT_STATE;
/* issue a quit command */
sprintf(tmpstring,"quit\r\n");
sendit(mp,tmpstring);
}
}
/* return true if the passed string contains a positive response code */
affirmative(mp)
struct smtp_msg *mp;
{
/* 2 is always good, 3 is ok if we've just sent 'data' command */
if ((*mp->buf = '2') ||
((*mp->buf = '3') && (mp->state = CLI_DATA_STATE)))
return 1;
else return 0;
}
/* smtp receiver upcall routine. fires up the state machine to parse input */
static
void
smtp_rec(tcb,cnt)
struct tcb *tcb;
int16 cnt;
{
register struct smtp_msg *mp;
char *inet_ntoa(), c;
struct mbuf *bp;
/* may want a void line here for procedures used */
/* printf("SMTP_REC called\n"); */
mp = (struct smtp_msg *)tcb->user; /* point to our struct */
recv_tcp(tcb,&bp,cnt); /* suck up chars from low level routine */
/* Assemble input line in buffer, return if incomplete */
while(pullup(&bp,&c,1) == 1) {
switch(c) {
case '\r': /* strip cr's */
continue;
case '\n': /* line is finished, go do it! */
mp->buf[mp->cnt] = '\0';
smtp_transaction(mp);
break;
default: /* other chars get added to buffer */
mp->buf[mp->cnt++] = c;
break;
}
}
}
/* smtp transmitter ready upcall routine. twiddles cts flag */
static
void
smtp_cts(tcb,cnt)
struct tcb *tcb;
int16 cnt;
{
register struct smtp_msg *mp;
struct mbuf *bp;
char tmpstring[LINELEN];
char *cp;
int c;
/* printf("SMTP_CTS called\n"); */
mp = (struct smtp_msg *)tcb->user; /* point to our struct */
/* don't do anything until/unless we're supposed to be sending */
if(mp->state != CLI_SEND_STATE) return;
if((bp = alloc_mbuf(cnt)) == NULLBUF){
/* Hard to know what to do here */
return;
}
cp = bp->data;
while(cnt > 1 && (c = getc(mp->tfile)) != EOF){
*cp++ = c;
bp->cnt++;
cnt--;
}
if(bp->cnt != 0)
send_tcp(tcb,bp);
else
free_p(bp);
if(cnt > 1){ /* EOF seen */
sprintf(tmpstring,"\r\n.\r\n");
sendit(mp,tmpstring);
mp->state = CLI_UNLK_STATE;
}
}
/* smtp state change upcall routine. cans connection on error */
static
void
smtp_state(tcb,old,new)
struct tcb *tcb;
char old,new;
{
struct smtp_msg *mp;
/* printf("SMTP_STATE called, state=%u\n",new); */
mp = (struct smtp_msg *)tcb->user;
switch(new) {
case ESTABLISHED:
mp->state = CLI_OPEN_STATE; /* shouldn't be needed */
break;
case CLOSE_WAIT:
close_tcp(tcb); /* shut things down */
/* may want to do something here to shut down
the rest of the transaction? */
break;
case CLOSED:
del_tcp(tcb); /* hosed for good */
if(mp->filename != NULLCHAR)
free(mp->filename);
free((char *)mp);
break;
}
}
/* Send message back to server */
static
void
sendit(mp,message)
struct smtp_msg *mp;
char *message;
{
struct mbuf *bp,*qdata();
/* printf("SENDIT called: %s",message); */
bp = qdata(message,(int16)strlen(message));
send_tcp(mp->tcb,bp);
}